package cn.net.cfss.fgbp.gateway.service;

import cn.net.cfss.fgbp.base.common.GlobalConstants;
import cn.net.cfss.fgbp.base.constant.ErrCodeEnum;
import cn.net.cfss.fgbp.base.except.CodeException;
import cn.net.cfss.fgbp.base.util.IpUtils;
import cn.net.cfss.fgbp.base.util.StringUtils;
import cn.net.cfss.fgbp.base.util.UuidUtil;
import cn.net.cfss.fgbp.base.vo.UserVo;
import cn.net.cfss.fgbp.gateway.config.ConfigProperty;
import cn.net.cfss.fgbp.gateway.common.Constants;
import cn.net.cfss.fgbp.gateway.vo.GateWayApiDto;
import cn.net.cfss.fgbp.log.influxdb.ApiDto;
import cn.net.cfss.fgbp.log.statistics.LogDtoFactory;
import cn.net.cfss.fgbp.log.util.LogStandardUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class VerifyService {

    @Autowired
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    private Integer syncWebExchange=1;

    public void auth(UserVo user,String url)
    {
        if(url.startsWith("/FGBP"))
        {
            url=url.substring(url.indexOf("/",1));
        }
        List<Object> roles=redisTemplate.opsForList().range(Constants.REDIS_KEY_PRE_USER_ROLES+user.getUserId(),0,-1);
        for(Object roleIdObj:roles)
        {
            Long roleId=null;
            if(roleIdObj instanceof List)
            {
                roleId=((List<Long>) roleIdObj).get(0);
            }
            String menuKey=Constants.REDIS_KEY_PRE_ROLE_MENU+roleId;
            List<String> menus=stringRedisTemplate.opsForList().range(menuKey,0,-1);
            if(menus.indexOf(url)>-1)
            {
                return;
            }
        }
        //找不到就是没有权限
        throw new CodeException(ErrCodeEnum.E401);
    }

    public UserVo updateTokenTime(String token)
    {
        Object object=redisTemplate.opsForValue().get(token);
        if(object==null)
        {
            log.error("redis查不到相关的token，请查看redis是否配置正确或token是真的失效了");
            throw new CodeException(ErrCodeEnum.E402);
        }
        UserVo user= (UserVo)object;
        redisTemplate.expire(token,ConfigProperty.getIns().tokenExpireTime , TimeUnit.MILLISECONDS);
        user.setNewToken(token);
        return user;
    }

    /**
     * 刷新门户第二token时使用，兼容平台门户与商家门户使用独立token的办法
     *
     * @param secondToken 门户第二token，即非当前正在使用的token
     */
    public void updateSecondTokenTime(String secondToken){
        redisTemplate.expire(secondToken, ConfigProperty.getIns().tokenExpireTime, TimeUnit.MILLISECONDS);
    }

    public synchronized void createApiDto(ServerHttpRequest originalRequest) {
        String url = originalRequest.getURI().getPath();
        String serverName=null;
        StringBuffer methodName=new StringBuffer();
        String[] strs=url.split("/");
        int i=0;
        if(StringUtils.isEmpty(strs[i]))
        {
            i++;
        }
        serverName=strs[i];
        i++;
        for(;i<strs.length;i++ ) {
            methodName.append(strs[i]).append("_");
        }
        methodName.deleteCharAt(methodName.length()-1);
        String acessParty= IpUtils.getIpAddr( originalRequest);//originalRequest.getHeaders().getFirst(GlobalConstants.HEADER_ACESS_PARTY);
        String trace= UuidUtil.getUUID();
        String span=String.valueOf(GlobalConstants.VAL_HEADER_GLOBAL_SPANID);//作为序号来用
        originalRequest.mutate().header(GlobalConstants.HEADER_GLOBAL_REQID,trace);
        originalRequest.mutate().header(GlobalConstants.HEADER_GLOBAL_SPANID,span);
        originalRequest.mutate().header(GlobalConstants.HEADER_FEIGN_CLIENT, ConfigProperty.getIns().appName);
        originalRequest.mutate().header(Constants.H_METHOD_NAME, methodName.toString());
        originalRequest.mutate().header(Constants.H_SERVER_NAME, serverName);
        originalRequest.mutate().header(Constants.H_BEGIN_TIMESTAMP, System.currentTimeMillis()+"");
        LogStandardUtil.extendLogV3(trace, span, "AuthFilter", "filter", "", acessParty, "", "", ConfigProperty.getIns().appVersion);
        log.info("url[{}]", url);


    }



    public Mono<Void> skipAuth( GatewayFilterChain chain, ServerWebExchange exchange)
    {
        ServerHttpRequest originalRequest = exchange.getRequest();

        //此url包括此串为固定不鉴权
        if(originalRequest.getURI().getPath().indexOf(Constants.NO_AUTH_ID)>-1)
        {
            return chain.filter(exchange);
        }
        List<String> skipAuthUrls= Arrays.asList(ConfigProperty.getIns().skipAuthUrls);
        for(String skipAuthUrl:skipAuthUrls)
        {
            //支持正则表达式,不建议使用此种配置方式，防止配错产生的严重后果
            if(skipAuthUrl.startsWith("|regex|"))
            {
                String regex=skipAuthUrl.substring(7);
                if(originalRequest.getURI().getPath().matches(regex))
                {
                    return chain.filter(exchange).subscriberContext(ctx -> ctx.put("", originalRequest));
                }
            }
            //使用开头匹配
            else  if(originalRequest.getURI().getPath().startsWith(skipAuthUrl))
            {
                return chain.filter(exchange);
            }
        }
        return null;
    }

    /*private ServerWebExchange createServerWebExchange(ServerWebExchange exchange,ApiDto apiDto)
    {
        synchronized (syncWebExchange) {
            ServerHttpRequest originalRequest = exchange.getRequest();
            ServerHttpRequest.Builder builder = originalRequest.mutate();
            builder.header(GlobalConstants.HEADER_GLOBAL_REQID, apiDto.getTrace());
            builder.header(GlobalConstants.HEADER_GLOBAL_SPANID, apiDto.getSpan());
            builder.header(GlobalConstants.HEADER_FEIGN_CLIENT, ConfigProperty.getIns().appName);
            ServerWebExchange mutableExchange = exchange.mutate().request(builder.build()).build();
            return mutableExchange;
        }
    }*/

//    public static void main(String[] args) {
//        String urlstr="|regex|/[a-zA-Z\\-]*/actuator,/auth,/unified/auth,/token/refresh,/FGBP-AUTH/auth,/FGBP-AUTH/auth/captcha,/FGBP-AUTH/unified/auth,/FGBP-FACE-UNIFIEDAPI,/YINYAN-FACE-ACCESS,/FGBP-GATEWAY,/FGBP-AUTH/test,/FGBP-FACE-PORTAL/portal/wechat,/FGBP-FACE-CALL/call/callVoice,/RUNFGBP-FACE-CRMDATA/doBusiness/root/survey/TexaminePaper,/RUNFGBP-FACE-CRMDATA/doBusiness/root/survey/TgetPaperByRelationAndSurvey,/RUNFGBP-FACE-CRMDATA/crmfile,/FGBP-FACE-CALL/ws,/FGBP-FACE-PORTAL/portal/question/invest,/FGBP-FACE-PORTAL/portal/wechat/,/FGBP-FACE-OPERATION/operation/activate,/FGBP-FACE-SELLER/actuator";
//        String[] skipAuthUrls=urlstr.split(",");
//        String url="/FGBP-FACE-REPORT/actuator";
//        for(String skipAuthUrl:skipAuthUrls)
//        {
//            if(skipAuthUrl.startsWith("|regex|"))
//            {
//                String regex=skipAuthUrl.substring(7);
//                if(url.matches(regex))
//                {
//                    System.out.println(skipAuthUrl+"true");
//                }
//            }
//            else if(url.startsWith(skipAuthUrl))
//            {
//                System.out.println(skipAuthUrl+"true");
//            }
//            else {
//                System.out.println(skipAuthUrl+"false");
//            }
//        }
//
//    }
}
